# flake8: noqa

import datetime
import traceback
from typing import Union

from coin.exchange.base.kr_rest.py_product import PyProduct
from coin.base.datetime_util import to_timestamp_int
from coin.strategy.mm.subscription import (SubscriptionRequest)


def generate_product_impl(f,
                          market_type,
                          exchange,
                          api_version,
                          norm_product,
                          current_datetime=None):
  current_datetime = current_datetime if current_datetime is not None \
                     else datetime.datetime.now()
  errstr = ""
  try:
    return PyProduct.from_norm(
        f'{market_type}:{exchange}:{norm_product}',
        to_timestamp_int(current_datetime))
  except Exception as e:
    errstr += traceback.format_exc()
  try:
    return PyProduct.from_native(
        f'{market_type}:{exchange}:{api_version}:{norm_product}',
        to_timestamp_int(current_datetime))
  except Exception as e:
    errstr += traceback.format_exc()
  raise ValueError("Unable to parse: %s, %s\n%s" % (
      f'{market_type}:{exchange}:{api_version}:{norm_product}',
      current_datetime,
      errstr))


def generate_product_from_str2(market_type,
                               exchange,
                               api_version,
                               norm_product: str,
                               current_datetime=None):
  assert isinstance(norm_product, str)
  return generate_product_impl(lambda x: x.FromStr,
                               market_type,
                               exchange,
                               api_version,
                               norm_product,
                               current_datetime)


def generate_product_from_subsymbol(mean, current_datetime=None):
  mark, exch, api, normp = mean.split(":")
  return generate_product_from_str2(mark, exch, api, normp, current_datetime)


def generate_product_from_subreq2(subreq, norm_product: str, current_datetime=None):
  assert isinstance(subreq, SubscriptionRequest)
  assert isinstance(norm_product, str)
  return generate_product_impl(lambda x: x.FromStr,
                               subreq.market_type,
                               subreq.exchange,
                               subreq.api_version,
                               norm_product,
                               current_datetime)


def _convert_api_version(market_type, exchange, api_version):
  if exchange in ('Huobi', 'Okex', 'Kraken') and market_type == 'Futures':
    return 'futures'
  else:
    return api_version


def generate_product_from_str(exchange, api_version, norm_product: str, current_datetime=None):
  assert isinstance(norm_product, str)
  market_type = 'Spot'
  api_version_converted = _convert_api_version(market_type, exchange, api_version)
  return generate_product_impl(lambda x: x.FromStr,
                               market_type,
                               exchange,
                               api_version_converted,
                               norm_product,
                               current_datetime)


def generate_product_from_subreq(subreq, norm_product: str, current_datetime=None):
  assert isinstance(subreq, SubscriptionRequest)
  assert isinstance(norm_product, str)
  api_version_converted = _convert_api_version(subreq.market_type,
                                               subreq.exchange,
                                               subreq.api_version)
  return generate_product_impl(lambda x: x.FromStr,
                               subreq.market_type,
                               subreq.exchange,
                               api_version_converted,
                               norm_product,
                               current_datetime)
